// controllers/salesReturnController.js

const SalesReturn = require("../models/SalesReturn");
const Sales = require("../models/Sales");
const Warehouse = require("../models/warehouseModel");
const CustomerData = require("../models/customerDataModel");
const Item = require("../models/itemModel");
const PaymentType = require("../models/paymentTypeModel");
const Account = require("../models/accountModel");

// Create a new sales return by referencing a sale using its referenceNo
exports.createReturn = async (req, res) => {
  try {
    const {
      originalSaleRef,        // user-provided sale reference number, e.g. "INV-1005"
      returnCode,
      referenceNo,
      returnDate,
      warehouse,
      customer,
      items,
      totalRefund,
      status,                 // "Return" or "Cancel"
      note,
      otherCharges,
      discountCouponCode,
      couponType,
      couponValue,
      discountOnAll,
      payments,
    } = req.body;

    // Validate basics. If you consider all mandatory, do so here:
    if (!originalSaleRef || !returnCode || !warehouse || !customer || !items?.length) {
      return res.status(400).json({ message: "Missing required fields!" });
    }

    // Attempt to find the sale by referenceNo
    const saleDoc = await Sales.findOne({ referenceNo: originalSaleRef });
    if (!saleDoc) {
      return res
        .status(404)
        .json({ message: `No sale found with referenceNo: ${originalSaleRef}` });
    }

    const warehouseDoc = await Warehouse.findById(warehouse);
    if (!warehouseDoc) {
      return res.status(404).json({ message: "Warehouse not found!" });
    }

    const customerDoc = await CustomerData.findById(customer);
    if (!customerDoc) {
      return res.status(404).json({ message: "Customer not found!" });
    }

    const validItems = [];
    for (const it of items) {
      const itemDoc = await Item.findById(it.item);
      if (!itemDoc) {
        return res
          .status(404)
          .json({ message: `Item not found: ${it.item}` });
      }
      validItems.push({
        item: itemDoc._id,
        quantity: it.quantity,
        reason: it.reason || "",
      });
    }

    // Validate or map payments array if needed
    const validPayments = [];
    if (payments && payments.length > 0) {
      for (const p of payments) {
        // optional check if PaymentType & Account exist
        if (p.paymentType) {
          const ptDoc = await PaymentType.findById(p.paymentType);
          if (!ptDoc) {
            return res
              .status(404)
              .json({ message: `PaymentType not found: ${p.paymentType}` });
          }
        }
        if (p.account) {
          const accDoc = await Account.findById(p.account);
          if (!accDoc) {
            return res
              .status(404)
              .json({ message: `Account not found: ${p.account}` });
          }
        }
        validPayments.push({
          paymentType: p.paymentType || null,
          account: p.account || null,
          amount: p.amount || 0,
          paymentNote: p.paymentNote || "",
          paymentDate: p.paymentDate || Date.now(),
        });
      }
    }

    // Build the new SalesReturn document
    const newReturn = new SalesReturn({
      sale: saleDoc._id,           // derived from saleDoc
      returnCode,
      referenceNo: referenceNo || "",
      returnDate: returnDate || new Date(),
      warehouse: warehouseDoc._id,
      customer: customerDoc._id,
      items: validItems,
      totalRefund: totalRefund || 0,
      status: status || "Return",
      note: note || "",
      otherCharges: otherCharges || 0,
      discountCouponCode: discountCouponCode || "",
      couponType: couponType || "",
      couponValue: couponValue || 0,
      discountOnAll: discountOnAll || 0,
      payments: validPayments,
    });

    // If authenticated user is present, set createdBy
    if (req.user && req.user.id) {
      newReturn.createdBy = req.user.id;
      newReturn.createdByModel =
        req.user.role.toLowerCase() === "admin" ? "Admin" : "User";
    }

    await newReturn.save();

    // If you have logic for certain statuses adjusting the customer's returnDue,
    // do it here. For example:
    // if (status === "Return") {
    //   customerDoc.salesReturnDue += newReturn.totalRefund;
    //   await customerDoc.save();
    // }

    res
      .status(201)
      .json({ message: "Return created successfully!", return: newReturn });
  } catch (error) {
    console.error(error);
    res
      .status(500)
      .json({ message: "Internal server error" });
  }
};

// Example for retrieving all returns
exports.getAllReturns = async (req, res) => {
  try {
    const returns = await SalesReturn.find()
      .populate("sale warehouse customer items.item")
      .populate("payments.paymentType payments.account")
      .populate("createdBy", "name FirstName LastName email");

    // Summaries if needed
    const totalCount = await SalesReturn.countDocuments({});
    const totalRefundAgg = await SalesReturn.aggregate([
      { $group: { _id: null, total: { $sum: "$totalRefund" } } },
    ]);
    const totalRefunded = totalRefundAgg.length ? totalRefundAgg[0].total : 0;

    const processed = returns.map((doc) => {
      let creatorName = "";
      if (doc.createdBy) {
        if (doc.createdByModel === "Admin" && doc.createdBy.name) {
          creatorName = doc.createdBy.name;
        } else if (doc.createdBy.FirstName && doc.createdBy.LastName) {
          creatorName = `${doc.createdBy.FirstName} ${doc.createdBy.LastName}`;
        }
      }
      return { ...doc.toObject(), creatorName };
    });

    res.status(200).json({
      summary: { totalCount, totalRefunded },
      returns: processed,
    });
  } catch (err) {
    console.error(err);
    res.status(500).json({ message: "Internal server error" });
  }
};

// Retrieve a single return by ID
exports.getReturnById = async (req, res) => {
  try {
    const returnDoc = await SalesReturn.findById(req.params.id)
      .populate("sale warehouse customer items.item")
      .populate("payments.paymentType payments.account")
      .populate("createdBy", "name FirstName LastName email");
    if (!returnDoc) {
      return res.status(404).json({ message: "Return not found!" });
    }
    let creatorName = "";
    if (returnDoc.createdBy) {
      if (returnDoc.createdByModel === "Admin" && returnDoc.createdBy.name) {
        creatorName = returnDoc.createdBy.name;
      } else if (returnDoc.createdBy.FirstName && returnDoc.createdBy.LastName) {
        creatorName = `${returnDoc.createdBy.FirstName} ${returnDoc.createdBy.LastName}`;
      }
    }
    const processed = { ...returnDoc.toObject(), creatorName };
    res.status(200).json(processed);
  } catch (err) {
    console.error(err);
    res
      .status(500)
      .json({ message: "Internal server error" });
  }
};

// Update a return
exports.updateReturn = async (req, res) => {
  try {
    const { id } = req.params;
    const oldReturn = await SalesReturn.findById(id);
    if (!oldReturn) {
      return res.status(404).json({ message: "Return not found!" });
    }

    // If you want to re-lookup warehouse, sale, etc. or re-validate items, you'd do it here
    const updatedReturn = await SalesReturn.findByIdAndUpdate(
      id,
      req.body,
      { new: true }
    )
      .populate("sale warehouse customer items.item")
      .populate("payments.paymentType payments.account")
      .populate("createdBy", "name FirstName LastName email");
    if (!updatedReturn) {
      return res.status(404).json({ message: "Return not found after update!" });
    }

    let creatorName = "";
    if (updatedReturn.createdBy) {
      if (updatedReturn.createdByModel === "Admin" && updatedReturn.createdBy.name) {
        creatorName = updatedReturn.createdBy.name;
      } else if (
        updatedReturn.createdBy.FirstName &&
        updatedReturn.createdBy.LastName
      ) {
        creatorName = `${updatedReturn.createdBy.FirstName} ${updatedReturn.createdBy.LastName}`;
      }
    }
    const processed = { ...updatedReturn.toObject(), creatorName };
    res.status(200).json({
      message: "Return updated successfully!",
      return: processed,
    });
  } catch (err) {
    console.error(err);
    res
      .status(500)
      .json({ message: "Internal server error" });
  }
};

// Delete a return
exports.deleteReturn = async (req, res) => {
  try {
    const returnDoc = await SalesReturn.findById(req.params.id);
    if (!returnDoc) {
      return res.status(404).json({ message: "Return not found!" });
    }
    await SalesReturn.findByIdAndDelete(req.params.id);
    res.status(200).json({ message: "Return deleted successfully!" });
  } catch (err) {
    console.error(err);
    res
      .status(500)
      .json({ message: "Internal server error" });
  }
};
